import { defineStore } from 'pinia';
import { computed, unref } from 'vue';

import useDownload from '@/hooks/useDownload';
import { useMessage } from '@/hooks/useMessage';
import { useI18n } from '@/locale/index';
import manifestJson from '@/manifest.json';
import { isFunction, isString } from '@/utils/is';
import { platform } from '@/utils/platform';
import { ErrorMessageMode } from '#/request';

import { defaultCheckApi } from './data';
import { AppInfo, UpgradeInfo, UpgraderOptions, UpgraderOptionsInternal } from './types';

/** 默认升级信息状态 */
const defaultUpgradeStatus: UpgradeInfo = {
  need: false,
  force: false,
  silent: false,
  wgt: false,
  size: 0,
  version: '',
  versionCode: '',
  author: '',
  email: '',
  url: '',
  title: '',
  content: '',
  appStoreLink: false,
};
/** 默认选项 */
export const defaultOptions: UpgraderOptionsInternal = {
  zIndex: 99,
  title: '',
  appInfo: null,
  errorMessageMode: 'modal',
  show: false,
  checked: false,
  upgrade: defaultUpgradeStatus,
  showProgress: false,
};

/** 升级程序存储 */
export const useUpgraderStore = defineStore(
  'app-upgrader',
  () => {
    const { t } = useI18n();
    const { toast, modal } = useMessage();
    const {
      run: runDownload,
      abort: abortDownload,
      data: dataDownload,
      progress: progressDownload,
    } = useDownload('', false, 'modal');

    /** 状态信息 */
    const state = ref<{ [key: string]: UpgraderOptionsInternal }>({});

    /** 获取处理进度 */
    const getProgress = computed<OnProgressEvent>(() => unref(progressDownload));

    /** 获取选项 */
    const getOptions = (key: string): UpgraderOptionsInternal => {
      const options = state.value[key] || defaultOptions;
      return options;
    };
    /** 获取应用信息 */
    const getAppInfo = (key: string): AppInfo => {
      let appInfo = getOptions(key)?.appInfo;
      if (!appInfo) {
        // #ifdef APP-PLUS
        appInfo = {
          ...appInfo,
          AppId: manifestJson.appid,
          Name: manifestJson.name,
          Descript: manifestJson.description,
          Version: manifestJson.versionName,
          VersionCode: manifestJson.versionCode,
          Author: manifestJson.developer?.name,
          Email: manifestJson.developer?.email,
          Platform: uni.getSystemInfoSync().platform,
        };
        // 这个貌似是异步处理，并且调试模式下获取的appid好像有问题 "HBuilder"。
        // plus.runtime.getProperty(plus.runtime.appid, function (widgetInfo) {
        //   appInfo = {
        //     ...appInfo,
        //     AppId: widgetInfo.appid,
        //     Name: widgetInfo.name,
        //     Descript: widgetInfo.description,
        //     Version: widgetInfo.version,
        //     VersionCode: widgetInfo.versionCode,
        //     Author: widgetInfo.author,
        //     Email: widgetInfo.email,
        //     Platform: uni.getSystemInfoSync().platform,
        //   };
        // });
        // #endif
        // #ifndef APP-PLUS
        appInfo = {
          ...appInfo,
          AppId: manifestJson.appid,
          Name: manifestJson.name,
          Descript: manifestJson.description,
          Version: manifestJson.versionName,
          VersionCode: manifestJson.versionCode,
          Author: manifestJson.developer?.name,
          Email: manifestJson.developer?.email,
          Platform: platform,
        };
        // #endif
      }
      return appInfo;
    };
    /** 获取版本描述 */
    const getVersion = (key: string) => {
      let retversion = '';
      const info = getAppInfo(key);
      const version = getOptions(key)?.upgrade?.version;
      retversion = info?.Version ? `${info.Version}${version ? ` -> ${version}` : ''}` : '';
      return retversion;
    };

    /** 获取显示 */
    const getShow = (key: string) => getOptions(key).show;
    /** 获取标题 */
    const getTitle = (key: string) => getOptions(key).title;
    /** 获取升级信息 */
    const getUpgrade = (key: string) => getOptions(key).upgrade;
    /** 获取显示进度 */
    const getShowProgress = (key: string) => getOptions(key).showProgress;

    /** 设置选项 */
    const setOptions = (key: string, options?: UpgraderOptions) => {
      setOptionsInternal(key, {
        zIndex: options?.zIndex || defaultOptions.zIndex,
        title: options?.title || defaultOptions.title,
        appInfo: options?.appInfo || defaultOptions.appInfo,
        errorMessageMode: options?.errorMessageMode || defaultOptions.errorMessageMode,
      });
    };

    /** 设置选项-内部 */
    const setOptionsInternal = (key: string, options?: UpgraderOptionsInternal) => {
      state.value[key] = {
        ...(state.value[key] || defaultOptions),
        ...options,
      };
    };

    /** 检测升级
     * @param mode 错误消息提示模式
     * @param silent 静默检测
     * @param checkApi 检查更新接口函数
     */
    async function check(
      key: string,
      mode?: ErrorMessageMode,
      silent: boolean = false,
      checkApi: typeof defaultCheckApi = defaultCheckApi,
    ) {
      try {
        if (!silent) {
          setOptionsInternal(key, { show: true });
        }
        toast.loading({
          content: t('common.loading'),
          mask: true,
        });
        if (!mode) {
          mode = getOptions(key).errorMessageMode;
        }
        if (checkApi && isFunction(checkApi)) {
          const appInfo = getAppInfo(key);
          const dto = {
            Code: appInfo.AppId,
            Platform: appInfo.Platform,
          };
          const result = await checkApi(dto, appInfo.VersionCode, mode);
          toast.hideLoading();
          if (result) {
            setOptionsInternal(key, { upgrade: result });
            if (result.need === true) {
              setOptionsInternal(key, { title: t('component.upgrade.newVersion') });

              if (result.force) {
                await upgrade(key);
              }
            } else {
              setOptionsInternal(key, { title: t('component.upgrade.latestVersion') });
            }
            setOptionsInternal(key, { checked: true });
          } else {
            setOptionsInternal(key, { upgrade: defaultUpgradeStatus, checked: false });
          }
        }
        toast.hideLoading();
      } catch (err) {
        console.error(err);
        setOptionsInternal(key, { checked: false });
        if (mode === 'modal') {
          modal.alert({
            title: t('component.upgrade.upgradeFailed'),
            content: isString(err) ? err : JSON.stringify(err),
            showCancel: false,
          });
        } else if (mode === 'message') {
          toast.error({
            content: isString(err) ? err : JSON.stringify(err),
          });
        }
      } finally {
        toast.hideLoading();
      }
      return getOptions(key).upgrade;
    }

    /** 处理升级
     * @param mode 错误消息提示模式
     */
    async function upgrade(key: string, mode?: ErrorMessageMode) {
      const options = getOptions(key);
      if (!mode) {
        mode = options.errorMessageMode;
      }
      if (!options.checked) {
        options.upgrade = await check(key, mode);
      }
      if (options.checked) {
        setOptionsInternal(key, { show: true });
        const platform = uni.getSystemInfoSync().platform;
        if (platform === 'ios' || options.upgrade.appStoreLink) {
          // 如果启用ios appstore升级，则打开appstore
          setOptionsInternal(key, { show: false });
          // console.log("跳转至appstore");
          // #ifdef APP-PLUS
          plus.runtime.launchApplication(
            {
              action: options.upgrade.url,
              // action: `itms-apps://itunes.apple.com/cn/app/id${getAppInfo.value.AppId}?mt=8`,
            },
            function (err) {
              console.error(err);
              if (mode === 'modal') {
                modal.alert({
                  title: t('component.upgrade.openAppStoreFailed'),
                  content: isString(err) ? err : JSON.stringify(err),
                  showCancel: false,
                });
              } else if (mode === 'message') {
                toast.error({
                  content: isString(err) ? err : JSON.stringify(err),
                });
              }
            },
          );
          // #endif
        } else {
          setOptionsInternal(key, { showProgress: true });
          const downloadurl = options.upgrade.url;
          await runDownload(downloadurl, null, false, mode);

          const tempFilePath = dataDownload.value?.tempFilePath;
          if (tempFilePath) {
            setOptionsInternal(key, { show: false });
            // 开始安装
            // #ifdef APP-PLUS
            plus.runtime.install(
              tempFilePath,
              {
                force: true,
              },
              function () {
                plus.runtime.restart();
              },
              function (err) {
                console.error(err);
                if (mode === 'modal') {
                  modal.alert({
                    title: t('component.upgrade.installFailed'),
                    content: isString(err) ? err : JSON.stringify(err),
                    showCancel: false,
                  });
                } else if (mode === 'message') {
                  toast.error({
                    content: isString(err) ? err : JSON.stringify(err),
                  });
                }
              },
            );
            // #endif
          }
        }
      }
    }

    /** 取消升级 */
    async function abort(key: string) {
      if (getShowProgress(key)) {
        setOptionsInternal(key, { showProgress: false });
        await abortDownload();
      }
    }

    /** 设置窗口显示 */
    async function show(key: string, show: boolean) {
      setOptionsInternal(key, { show });
      if (show) {
        await check(key);
      }
    }

    /** 关闭窗口显示 */
    async function close(key: string) {
      await show(key, false);
    }

    return {
      /** 状态信息 */
      state,
      /** 获取处理进度 */
      getProgress,
      /** 获取选项 */
      getOptions,
      /** 获取应用信息 */
      getAppInfo,
      /** 获取版本描述 */
      getVersion,
      /** 获取显示 */
      getShow,
      /** 获取标题 */
      getTitle,
      /** 获取升级信息 */
      getUpgrade,
      /** 获取显示进度 */
      getShowProgress,
      /** 设置选项 */
      setOptions,
      /** 检测升级 */
      check,
      /** 处理升级 */
      upgrade,
      /** 取消升级 */
      abort,
      /** 设置窗口显示 */
      show,
      /** 关闭窗口显示 */
      close,
    };
  },
  {
    persist: false, // 如果需要持久化就写 true, 不需要持久化就写 false（或者去掉这个配置项）。
  },
);
